<?php
/*
 * program:	均源
 * author:	雨中漫步 & 上善若水 & qhxin
 * email:	qhxin@qhxin.com
 * date:	2014/11/11
 * description:	又是一年双十一，不能剁手，就写点东西吧~~~~~~
 */

defined('IN_SCHOOL') or die();

/*{TranslateTagBegin}*/

class core {

	public static $installed_plugin_conf = array();

	/*
	功能：获取以下全局数组数据：GET|POST|COOKIE|REQUEST|SERVER
	*/
	public static function gpc($k, $var = 'G') {
		switch($var) {
			case 'G': $var = &$_GET; break;
			case 'P': $var = &$_POST; break;
			case 'C': $var = &$_COOKIE; break;
			case 'R': $var = isset($_GET[$k]) ? $_GET : (isset($_POST[$k]) ? $_POST : $_COOKIE); break;
			case 'S': $var = &$_SERVER; break;
		}
		return isset($var[$k]) ? $var[$k] : NULL;
	}
	
	/*
	反斜线转义
	*/
	public static function addslashes(&$var) {
		if(is_array($var)) {
			foreach($var as $k=>&$v) {
				self::addslashes($v);
			}
		} else {
			$var = addslashes($var);
		}
		return $var;
	}
	
	/*
	反转义反斜线
	如果 magic_quotes_sybase 项开启，反斜线将被去除，但是两个反斜线将会被替换成一个。 
	*/
	public static function stripslashes(&$var) {
		if(is_array($var)) {
			foreach($var as $k=>&$v) {
				self::stripslashes($v);
			}
		} else {
			$var = stripslashes($var);
		}
		return $var;
	}
	
	/*
	转义HTML实体
	*/
	public static function htmlspecialchars(&$var) {
		if(is_array($var)) {
			foreach($var as $k=>&$v) {
				self::htmlspecialchars($v);
			}
		} else {
			$var = str_replace(array('&', '"', '<', '>'), array('&amp;', '&quot;', '&lt;', '&gt;'), $var);
		}
		return $var;
	}
	
	/*
	此编码与 WWW 表单 POST 数据的编码方式一样
	同时与 application/x-www-form-urlencoded 的媒体类型编码方式一样
	*/
	public static function urlencode($s) {
		$s = urlencode($s);
		return str_replace('-', '%2D', $s);
	}
	
	/*
	解码urlencode
	*/
	public static function urldecode($s) {
		return urldecode($s);
	}
	
	/*
	json数据解码
	*/
	public static function json_decode($s) {
		return $s === FALSE ? FALSE : json_decode($s, 1);
	}
	
	/*
	替代 json_encode
	json数据编码
	*/
	public static function json_encode($data) {
		if(is_array($data) || is_object($data)) {
			$islist = is_array($data) && (empty($data) || array_keys($data) === range(0,count($data)-1));
			if($islist) {
				$json = '['.implode(',', array_map(array('core', 'json_encode'), $data)).']';
			} else {
				$items = Array();
				foreach($data as $key => $value) $items[] = self::json_encode("$key").':'.self::json_encode($value);
				$json = '{'.implode(',', $items).'}';
			}
		} elseif(is_string($data)) {
			$string = '"'.addcslashes($data, "\\\"\n\r\t/".chr(8).chr(12)).'"';
			$json   = '';
			$len    = strlen($string);
			for($i = 0; $i < $len; $i++ ) {
				$char = $string[$i];
				$c1   = ord($char);
				if($c1 <128 ) { 
					$json .= ($c1 > 31) ? $char : sprintf("\\u%04x", $c1);
					continue;
				}
				$c2 = ord($string[++$i]);
				if (($c1 & 32) === 0) {
					$json .= sprintf("\\u%04x", ($c1 - 192) * 64 + $c2 - 128);
					continue;
				}
				$c3 = ord($string[++$i]);
				if(($c1 & 16) === 0) {
					$json .= sprintf("\\u%04x", (($c1 - 224) <<12) + (($c2 - 128) << 6) + ($c3 - 128));
					continue;
				}
				$c4 = ord($string[++$i]);
				if(($c1 & 8 ) === 0) {
					$u = (($c1 & 15) << 2) + (($c2>>4) & 3) - 1;
					$w1 = (54<<10) + ($u<<6) + (($c2 & 15) << 2) + (($c3>>4) & 3);
					$w2 = (55<<10) + (($c3 & 15)<<6) + ($c4-128);
					$json .= sprintf("\\u%04x\\u%04x", $w1, $w2);
				}
			}
		}  else {
			$json = strtolower(var_export( $data, true ));
		}
		return $json;
	}
	
	/*
	带证书的插件
	*/
	public static function plugin_payed_relic(&$s, $p) {
		$c = str_replace(CONFIG_PLG_PATH,'',$p);
		$c = explode('/', $c);
		if(!isset($c[1])) return;
		$p = CONFIG_PLG_PATH.$c[0].'/JY_PLG_LICENSE';
		if(is_file($p)) {
			$s = Tran::elic($s, file_get_contents($p), USER_KEY, md5($c[0].$c[1]));
		}
	}
	
	/*
	获取插件配置信息
	*/
	public static function plugin_list_installed() {
		$plg_conf_json_file = CONFIG_PATH. 'config_plugin.json';
		!file_exists($plg_conf_json_file) && file_put_contents($plg_conf_json_file,
							core::json_encode(array('baseinfo'=>array(),
							'controls'=>array(),'models'=>array(),'template'=>array(),
							'phphooks'=>array(),'tplhooks'=>array(),)),LOCK_EX);
		core::$installed_plugin_conf =  (array)core::json_decode(file_get_contents($plg_conf_json_file));
	}
	
	/*
	插件模板挂载
	*/
	public static function hooks_process_view(&$s) {
		$hookname = isset($s[1]) ? $s[1]:'';
		$error = $result = NULL;
		!isset(core::$installed_plugin_conf['tplhooks']) && $error = 1;
		!isset(core::$installed_plugin_conf['baseinfo']) && $error = 1;
		if($error) return '';
		foreach(core::$installed_plugin_conf['tplhooks'] as $rand=>$arr) {
			if(!in_array($hookname,$arr)) continue;
			$id = core::$installed_plugin_conf['baseinfo'][$rand]['id'];
			$hookpath = CONFIG_PLG_PATH.$id."/$hookname.htm";
			$hookstr = file_get_contents($hookpath);
			self::plugin_payed_relic($hookstr, $hookpath);
			$result .= "$hookstr\n\n";
		}
		return $result;
	}
	
	/*
	插件框架挂载
	*/
	public static function hooks_process_mc($hookname) {
		$error = $result = NULL;
		!isset(core::$installed_plugin_conf['phphooks']) && $error = 1;
		!isset(core::$installed_plugin_conf['baseinfo']) && $error = 1;
		if($error) return '';
		foreach(core::$installed_plugin_conf['phphooks'] as $rand=>$arr) {
			if(!in_array($hookname,$arr)) continue;
			$id = core::$installed_plugin_conf['baseinfo'][$rand]['id'];
			$hookpath = CONFIG_PLG_PATH.$id."/$hookname.php";
			$hookstr = Tran::translate($hookpath);
			self::plugin_payed_relic($hookstr, $hookpath);
			$result .= "$hookstr\n\n";
		}
		return $result;
	}
	
	/*
	框架挂载点
	*/
	public static function hooks_match_process(&$s) {
		$a = array();
		preg_match_all('/\/\/hook ([0-9a-zA-Z_]+)\.php/',$s,$a);
		foreach($a[1] as $k=>$hookname) {
			$t = self::hooks_process_mc($hookname);
			$s = str_replace($a[0][$k] ,$t ,$s);
		}
	}
	
	/*
	运行
	*/
	public static function run() {
		$control = core::gpc(0);
		$do		 = core::gpc(1);
		
		$ctr_name = 'control_'.($control != NULL ? $control: 'index');
		$do = 'do_'. ($do != NULL ? "$do" : 'index');
		
		self::plugin_list_installed();
		$_SERVER['jy_ctr_do'] = md5($ctr_name. "_$do" . CONFIG_CS_KEY);
		$_SERVER['jy_ctr_nm'] = $ctr_name;
		
		$ctr_do_tmp_path = CONFIG_TMP_PATH. 'tmp.ctr.'.$_SERVER['jy_ctr_do'] .'.php';
		$ctr_path = CONFIG_CTR_PATH . "$ctr_name.php";
		$new_inc_control_file = file_exists($ctr_do_tmp_path)? false : true;
		clearstatcache();
		
		if(!file_exists( $ctr_path )) {
			clearstatcache();
			//插件control
			foreach(core::$installed_plugin_conf['controls'] as $rand=>$arr) {
				if(in_array($ctr_name,$arr)){
					$id = core::$installed_plugin_conf['baseinfo'][$rand]['id'];
					$ctr_path = CONFIG_PLG_PATH.$id."/$ctr_name.php";
					break;
				}
			}
			if(!file_exists($ctr_path)) {
				new Log("Unkown control file: $ctr_name, ip:". $_SERVER['ip']);
				html::html_locate('index.php');
			}
		}
		
		if(DEBUG || $new_inc_control_file) {
			$ctr_str = Tran::translate($ctr_path);
			misc::in_key_str($ctr_path, CONFIG_PLG_PATH) && self::plugin_payed_relic($ctr_str, $ctr_path); 
			//处理hook
			misc::in_key_str($ctr_path, CONFIG_CTR_PATH) && self::hooks_match_process($ctr_str);
			file_put_contents($ctr_do_tmp_path, 
				"<?php\ndefined('IN_SCHOOL') or die();\n\n".
				"/*{ExtTarget}*/\n\n/*{ModTarget}*/\n\n$ctr_str\n?>"
			,LOCK_EX);
		}

		if(file_exists( $ctr_do_tmp_path )) {
			require $ctr_do_tmp_path;
		}else{
			new Log("Unkown control tmp file: $ctr_name, ip:". $_SERVER['ip']);
			html::html_locate('index.php');
		}
		
		if(!class_exists($ctr_name, false)){
			new Log($ctr_name.' does not exists, ip:'.$_SERVER['ip']);
			html::html_locate('index.php');
		}
		$ctr = new $ctr_name;
		if(!method_exists($ctr, $do)){
			new Log("$ctr_name->$do()".' does not exists, ip:'.$_SERVER['ip']);
			html::html_locate('index.php');
		}
		try {
			$ctr->$do();
		} catch (Exception $e) {
			new Log( get_class($e).
						' thrown within the core::run(). Message: '.
						$e->getMessage().' on line '.$e->getLine());
			html::html_locate('index.php');
		}
	}
	
	/*
	初始化一些设置
	*/
	public static function init_set() {
		if(DEBUG) {
			error_reporting(E_ALL | E_STRICT);
			@ini_set('display_errors', 'Off');
		} else {
			error_reporting(E_ALL & ~E_NOTICE);
			@ini_set('display_errors', 'On');
		}
		
		// 关闭运行期间的自动增加反斜线
		@set_magic_quotes_runtime(0);
		
		// 最低版本需求判断
		PHP_VERSION < '5.0' && exit('Required PHP version 5.0.* or later.');	
	}

	/*
	记录异常日志
	*/
	public static function exception_handle($e) {		
		new Log($e->getMessage().' File: '.$e->getFile().' ['.$e->getLine().']');
		exit;
	}
	
	/*
	记录错误日志
	*/
	public static function error_handle($errno, $errstr, $errfile, $errline) {
		
		$errortype = array (
			E_ERROR	      => 'Error',
			E_WARNING	    => 'Warning',
			E_PARSE	      => 'Parsing Error',	# uncatchable
			E_NOTICE	     => 'Notice',
			E_CORE_ERROR	 => 'Core Error',		# uncatchable
			E_CORE_WARNING       => 'Core Warning',		# uncatchable
			E_COMPILE_ERROR      => 'Compile Error',	# uncatchable
			E_COMPILE_WARNING    => 'Compile Warning',	# uncatchable
			E_USER_ERROR	 => 'User Error',
			E_USER_WARNING       => 'User Warning',
			E_USER_NOTICE	=> 'User Notice',
			E_STRICT	     => 'Runtime Notice',
		);
		
		$errnostr = isset($errortype[$errno]) ? $errortype[$errno] : 'Unknonw';
	
		$s = "[$errnostr] : $errstr in File $errfile, Line: $errline";
		new Log($s);
		
		return 0;
	}
	
	/*
	修正 IIS  $_SERVER[REQUEST_URI]
	*/
	private static function fix_iis_request() {
		if(isset($_SERVER['HTTP_X_REWRITE_URL'])) {
			$_SERVER['REQUEST_URI'] = &$_SERVER['HTTP_X_REWRITE_URL'];
		} else if(isset($_SERVER['HTTP_REQUEST_URI'])) {
			$_SERVER['REQUEST_URI'] = &$_SERVER['HTTP_REQUEST_URI'];
		} else {
			if(isset($_SERVER['SCRIPT_NAME'])) {
				$_SERVER['HTTP_REQUEST_URI'] = $_SERVER['SCRIPT_NAME'];
			} else {
				$_SERVER['HTTP_REQUEST_URI'] = $_SERVER['PHP_SELF'];
			}
			if(isset($_SERVER['QUERY_STRING'])) {
				$_SERVER['REQUEST_URI'] = '?' . $_SERVER['QUERY_STRING'];
			} else {
				$_SERVER['REQUEST_URI'] = '';
			}
		}
	}
	/*
	 * 如下格式：
	 * user-login-page-2?xxx=123&yyy=ddd
	 * 解析后：
	 * $_GET = Array
		(
		    [0] => user
		    [1] => login
		    [2] => page
		    [3] => 2
		    [xxx] => 123
		    [yyy] => ddd
		    [page] => 2
		)*/
	private static function init_get() {
		$r = $_SERVER['REQUEST_URI'];
		
		// fix rewrite 导致的 .htm 变为 _htm
		if(strrpos($r, '_htm') !== FALSE) {
			$r = str_replace('_htm', '.htm', $r);		
		}
		
		
		$get = &$_GET;
		$query_string = core::gpc('QUERY_STRING', 'S'); // URL-REWRITE 后，此处为REWRITE后的值。
		parse_str($query_string, $get);
		
		$r = substr($r, strrpos($r, '/') + 1);				//第[1]步
		strtolower(substr($r, 0, 9)) == 'index.php' && $r = substr($r, 9);
		substr($r, 0, 1) == '?' && $r = substr($r, 1);

		//$r = preg_replace('#^/?([^/]+/(index\.php)?\??)*#', '', $r);	//第[1]步
		
		// 第一个分号作为分隔
		$r = str_replace('.htm&', '?', $r);				//第[2]步
		$r = str_replace('.htm?', '?', $r);				//第[3]步
		$sep = strpos($r, '?');						//第[4]步
		
		$s1 = $s2 = '';	// $s1 为 url 前半部分(格式：user-login-page-123), $s2 为后半部分(格式：user=login&page=2)。
		if($sep !== FALSE) {
			$s1 = substr($r, 0, $sep);
			$s2 = substr($r, $sep + 1);
		} else {
			$s1 = $r;
			$s2 = '';
			if(substr($s1, -4) == '.htm') {
				$s1 = substr($s1, 0, -4);			//第[5]步
			} else {
				$s2 = $s1;					//第[6]步
				$s1 = '';
			}
		}
		
		$arr1 = $arr2 = array();
		
		$s1 && $arr1 = explode('-', $s1);
		parse_str($s2, $arr2);
		$get += $arr1;
		$get += $arr2;
		
		$num = count($arr1);
		if($num > 2) {
			for($i=2; $i<$num; $i+=2) {
				isset($arr1[$i+1]) && $get[$arr1[$i]] = $arr1[$i+1];
			}		
		}
		
		$get[0] = isset($get[0]) && preg_match("/^\w+$/", $get[0]) ? $get[0] : 'index';
		$get[1] = isset($get[1]) && preg_match("/^\w+$/", $get[1]) ? $get[1] : 'index';
	}
	
	/*
	获取目录
	*/
	public static function get_paths($path, $fullpath = FALSE) {
		$arr = array();
		$df = opendir($path);
		while($dir = readdir($df)) {
			if($dir == '.' || $dir == '..' || $dir[0] == '.' || !is_dir($path.$dir)) continue;
			$arr[] = $fullpath ? $path.$dir.'/' : $dir;
		}
		sort($arr);// 根据名称从低到高排序
		return $arr;
		
	}
	
	/*
	初始化时区
	*/
	public static function init_timezone() {
		if(defined('CONFIG_TIMEOFFSET') && CONFIG_TIMEOFFSET!='') {
			$zones = array (
				'-12' => 'Kwajalein',
				'-11' => 'Pacific/Midway',
				'-10' => 'Pacific/Honolulu',
				'-9' => 'America/Anchorage',
				'-8' => 'America/Los_Angeles',
				'-7' => 'America/Denver',
				'-6' => 'America/Tegucigalpa',
				'-5' => 'America/New_York',
				'-4' => 'America/Halifax',
				'-3' => 'America/Sao_Paulo',
				'-2' => 'Atlantic/South_Georgia',
				'-1' => 'Atlantic/Azores',
				'0' => 'Europe/Dublin',
				'+1' => 'Europe/Belgrade',
				'+2' => 'Europe/Minsk',
				'+3' => 'Asia/Tehran',
				'+4' => 'Asia/Muscat',
				'+5' => 'Asia/Katmandu',
				'+6' => 'Asia/Rangoon',
				'+7' => 'Asia/Krasnoyarsk',
				'+8' => 'Asia/Shanghai',
				'+9' => 'Australia/Darwin',
				'+10' => 'Australia/Canberra',
				'+11' => 'Asia/Magadan',
				'+12' => 'Pacific/Fiji',
				'+13' => 'Pacific/Tongatapu',
			);
			// php 5.4 以后，不再支持 Etc/GMT+8 这种格式！
			if(isset($zones[CONFIG_TIMEOFFSET])) {
				date_default_timezone_set($zones[CONFIG_TIMEOFFSET]);
			}
		}
		
	}
	
	public static function is_HTTPS(){
		if(!isset($_SERVER['HTTPS'])) return FALSE;
		if($_SERVER['HTTPS'] === 1){  //Apache
			return TRUE;
		}elseif($_SERVER['HTTPS'] === 'on'){ //IIS
			return TRUE;
		}elseif($_SERVER['SERVER_PORT'] == 443){ //其他
			return TRUE;
		}
		return FALSE;
	}
	
	/*
	初始化
	*/
	public static function init() {
	
		core::init_timezone();
		core::init_set();
		
		// 将更多信息放入 $_SERVER 变量
		$_SERVER['starttime'] = core::getmicrotime();
		$_SERVER['time'] = isset($_SERVER['REQUEST_TIME']) ? $_SERVER['REQUEST_TIME'] : time();
		$_SERVER['ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
		$_SERVER['jy_ctr_do'] = '';
		$_SERVER['jy_ctr_nm'] = '';
		$_SERVER['jy_inc_mod'] = array();
		$_SERVER['jy_inc_ext'] = array();
		$_SERVER['http_protocol'] = self::is_HTTPS() ? 'https://': 'http://';
		
		// 兼容IIS $_SERVER['REQUEST_URI']
		(!isset($_SERVER['REQUEST_URI']) || (isset($_SERVER['HTTP_X_REWRITE_URL']) && $_SERVER['REQUEST_URI'] != $_SERVER['HTTP_X_REWRITE_URL'])) && self::fix_iis_request();
		
		$_GET = array();
		self::init_get();
		
		// GPC安全过滤
		if(get_magic_quotes_gpc()) {
			core::stripslashes($_GET);
			core::stripslashes($_POST);
			core::stripslashes($_COOKIE);
		}
		core::htmlspecialchars($_GET);
		if('admin' != core::gpc(0))
			core::htmlspecialchars($_POST);
		core::htmlspecialchars($_COOKIE);
		
		header("Content-type:text/html;charset=UTF-8");
		//header("Cache-Control: no-cache");
		//header("Pragma: no-cache");
		//header("Expires: 0");
		header('X-Powered-By: jy.qhxin.com;');
	}
	
	public static function getmicrotime() {
		list($usec, $sec) = explode(' ', microtime());
		return ((float)$usec + (float)$sec);
	}
	
	public static function acttime() {
		$time_end = core::getmicrotime();
		return '页面执行时间:'.(int)(($time_end - $_SERVER['starttime'])*1000).'毫秒';
	}

	/*
	GZIP
	*/
	public static function ob_gzip($content) {
		if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && !headers_sent() && extension_loaded('zlib') && strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip')!==false ){
			$content=gzencode($content, 6);
			header('Content-Encoding: gzip');
			header('Vary: Accept-Encoding'); 
			header('Content-Length: '.strlen($content));
		}
		return $content;
	}
	
	public static function ob_start() {
		ob_start('core::ob_gzip');
	}

}

/*{TranslateTagEnd}*/

?>